/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - core/system/io
// Copyright (c) 2014.  All Rights Reserved
//
// File:		AETypes.h
// Author:		Gianluca Belardelli
// Date:		08/10/2013
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AETYPES_H_
#define _AETYPES_H_

template< typename T > 
struct is_char
{ 
  static const bool value = false;
};

template< typename T > 
struct is_wchar
{ 
  static const bool value = false;
};

template<> 
struct is_char< char >
{ 
  static const bool value = true; 
};

template<> 
struct is_wchar< wchar_t >
{ 
  static const bool value = true; 
};

////////////////////////////////////////////////////////////////
//  Tipi base
////////////////////////////////////////////////////////////////

// Uncomment the next line if you want to build with double precision math
//#define AE_REAL_IS_DOUBLE

#if !defined(AE_REAL_IS_DOUBLE)
#define AE_REAL_IS_FLOAT
#endif

typedef unsigned long		AEUINT32;
typedef unsigned long		AEBOOL32;
typedef long				AEINT32;
typedef short				AEINT16;
typedef unsigned short		AEUINT16;
typedef char				AEINT8;
typedef unsigned char		AEUINT8;
typedef char				AECHAR;
typedef unsigned char		AEUCHAR;
typedef void				AEVOID;
typedef void*				AEVOIDPTR;
typedef float				AEFLOAT32;
typedef double				AEDOUBLE64;

typedef unsigned long		AERESULT;

#ifndef TRUE
#define TRUE	1
#endif

#ifndef FALSE
#define FALSE	0
#endif

#define AE_ALIGN_FLOAT AE_ALIGN16
#define AE_ALIGN_DOUBLE AE_ALIGN32
#define AE_FLOAT_ALIGNMENT 16
#define AE_DOUBLE_ALIGNMENT 32
#define AE_FLOAT_SIZE 4
#define AE_DOUBLE_SIZE 8

/// hkReal is the default floating point type.
#if defined(AE_REAL_IS_DOUBLE)
typedef AEDOUBLE64 AEREAL;
#define AE_ALIGN_REAL AE_ALIGN_DOUBLE
#define AE_REAL_ALIGNMENT AE_DOUBLE_ALIGNMENT
#define AE_REAL_SIZE AE_DOUBLE_SIZE
#else
typedef AEFLOAT32 AEREAL;
#define AE_ALIGN_REAL AE_ALIGN_FLOAT
#define AE_REAL_ALIGNMENT AE_FLOAT_ALIGNMENT
#define AE_REAL_SIZE AE_FLOAT_SIZE
#endif

#define	AE_SUCCESS			0x0001
#define AE_FAILURE			0x0000


#define AE_DECLARE_NON_COPYABLE(className) \
	private:\
		className( const className & );\
		void operator=( const className& )

#define AE_DECLARE_SINGLETON( className )\
		AE_DECLARE_NON_COPYABLE( className );\
	private:\
		className( void ) {};\
	public:\
		static className &GetInstance( void )\
		{\
			static className m_sInstance;\
			return m_sInstance;\
		}

/// Note that ALIGNMENT must be a power of two for this to work.
/// Note: to use this macro you must cast your pointer to a byte pointer or to an integer value.
#define AE_NEXT_MULTIPLE_OF(ALIGNMENT, VALUE)  ( ((VALUE) + ((ALIGNMENT)-1)) & (~((ALIGNMENT)+(VALUE)*0-1)) )

template <typename TYPE>
AE_FORCEINLINE TYPE* AddByteOffset( TYPE *base, AEUINT32 offset )
{
	return reinterpret_cast<TYPE*>( reinterpret_cast<AEUINT32>(base) + offset );
}


#define AESETBIT(Bit)                      ( 1U<<(Bit) )


/// Wrapper per manipolare bitfields con una grandezza esplicita.
template<typename BITS, typename STORAGE>
class AEFlags
{
private:
	STORAGE m_tStorage;

public:
	AE_FORCEINLINE AEFlags( void )				{ }
	AE_FORCEINLINE AEFlags( STORAGE s )			{ m_tStorage = s; }

	AE_FORCEINLINE void Clear( void )			{ m_tStorage = 0; }
	AE_FORCEINLINE void Clear( STORAGE tMask )	{ m_tStorage &= ~tMask; }
	AE_FORCEINLINE void SetAll( STORAGE tSet )	{ m_tStorage = tSet; }

	AE_FORCEINLINE void OrWith( STORAGE tOr )	{ m_tStorage |= tOr; }
	AE_FORCEINLINE void XorWith( STORAGE tXor )	{ m_tStorage ^= tXor; }
	AE_FORCEINLINE void AndWith( STORAGE tAnd )	{ m_tStorage &= tAnd; }

	AE_FORCEINLINE void SetWithMask( STORAGE tSet, STORAGE tMask )	{ m_tStorage = ( m_tStorage & ~tMask ) | ( tSet & tMask ); }
	
	AE_FORCEINLINE STORAGE Get( void ) const					{ return m_tStorage; }
	AE_FORCEINLINE STORAGE Get( STORAGE tMask ) const			{ return m_tStorage & tMask; }
	AE_FORCEINLINE bool AnyIsSet( STORAGE tMask ) const			{ return (m_tStorage & tMask); }
	AE_FORCEINLINE bool NoneIsSet( STORAGE tMask ) const		{ return (m_tStorage & tMask) == 0; }
	AE_FORCEINLINE bool AllAreSet( STORAGE tMask ) const		{ return (m_tStorage & tMask) == tMask; }

	AE_FORCEINLINE bool operator==( const AEFlags &flFlags ) const	{ return flFlags.m_tStorage == m_tStorage; }
	AE_FORCEINLINE bool operator!=( const AEFlags &flFlags ) const	{ return flFlags.m_tStorage ^ m_tStorage; }
};

template <typename T>
class AESingleton
{
	public:

		static T* s_instance;

			/// Get the instance of this singleton. This creates an instance when hkBaseSystem::init is called.
		static AE_FORCEINLINE T& getInstance()
		{
			return *AESingleton<T>::s_instance;
		}

			/// Remove a reference to the existing singleton and use the supplied one instead.
		static void replaceInstance(T* t)
		{
			/*if(hkSingleton<T>::s_instance)
			{
				hkSingleton<T>::s_instance->removeReferenceLockUnchecked();
			}*/
			AESingleton<T>::s_instance = t;
		}

		/// Remove a reference to the existing singleton and use the supplied one instead adding a reference to it.
		/*static void HK_CALL replaceInstanceAndAddReference(T* t)
		{
			t->addReferenceLockUnchecked();
			if (hkSingleton<T>::s_instance)
			{
				hkSingleton<T>::s_instance->removeReferenceLockUnchecked();
			}
			hkSingleton<T>::s_instance = t;			
		}*/

			/// Has this singleton been initialized?
		static bool isInitialised()
		{
			return AESingleton<T>::s_instance != NULL;
		}

	protected:

		AESingleton() { }

		AESingleton(const AESingleton&); //not implemented
		AESingleton& operator= (const AESingleton&); //not implemented
};

/// A wrapper to store a hkBool in one byte, regardless of compiler options.
class AEBool
{
// Members
private:
	char m_bBool;

// Methods
public:
	// used in compile time asserts
	typedef char CompileTimeTrueType;
	typedef int CompileTimeFalseType;

	AE_FORCEINLINE AEBool( void ) {}

	AE_FORCEINLINE  AEBool( bool bValue )
	{
		m_bBool = static_cast<char>( bValue );
	}

	operator bool() const
	{
		return m_bBool != 0;
	}

	AEBool& operator=( bool bValue )
	{
		m_bBool = static_cast<char>( bValue );
		return *this;
	}

	AEBool operator==( bool bValue ) const
	{
		return ( m_bBool != 0 ) == bValue;
	}

	AEBool operator!=( bool bValue ) const
	{
		return ( m_bBool != 0 ) != bValue;
	}
};

template <bool N> 
struct AETraitBool
{
	typedef AETraitBool<N> type;
	enum { result = N };
};

typedef AETraitBool<true> AETypeIsPod;
typedef AETraitBool<false> AETypeIsClass;

template <typename T>
AEBool::CompileTimeFalseType operator==( const T&, const AETypeIsPod& );

#if defined(__GCCXML__)
  template <typename T>
  struct AEIsPodType : public AETraitBool< ( sizeof( *static_cast<T*>( 0 ) == *static_cast<const AETypeIsPod*>( 0 ) ) == sizeof( AEBool::CompileTimeTrueType ) ) > {};
#else
  template <typename T>
  struct AEIsPodType : public AETraitBool< ( sizeof( *reinterpret_cast<T*>( 128 ) == *reinterpret_cast<const AETypeIsPod*>( 128 ) ) == sizeof( AEBool::CompileTimeTrueType ) ) > {};
#endif

// Type with one level of const removed: hkRemoveConst<int>::type is int, so is hkRemoveConst<const int>::type
template <typename T>
struct AERemoveConst
{
	typedef T type;
};

template <typename T>
struct AERemoveConst<const T>
{
	typedef T type;
};

// Checking for "const"
template <typename T>
struct AEIsConstType : public AETraitBool<false>
{};

template <typename T>
struct AEIsConstType<const T> : public AETraitBool<true>
{};

struct AEPlacementNewArg;
inline void* operator new( size_t, AEPlacementNewArg *lpPtr ) { return lpPtr; }
inline void* operator new[]( size_t, AEPlacementNewArg *lpPtr ) { return lpPtr; }
inline void operator delete( void* /*unused*/, AEPlacementNewArg* /*unused*/) { AEASSERT( false ); }
inline void operator delete[]( void* /*unused*/, AEPlacementNewArg* /*unused*/) { AEASSERT( false ); }

template <typename TYPE>
AE_FORCEINLINE const TYPE *AE_CALL AEAddByteOffsetConst( const TYPE *tBase, AEINT32 nOffset )
{
	return reinterpret_cast<const TYPE*>( reinterpret_cast<AEUINT32>( tBase ) + nOffset );
}

//macro to determine the size of a static array
template <typename T, size_t N> char (*AEArraySizeHelper( T (&)[N] ))[N];

// Add zero to avoid warnings when multiplying
// ARRAYSIZE and sizeof(arr[0])
#define AE_ARRAY_SIZE(A) (sizeof(*::AEArraySizeHelper(A))+0)

#endif // _AETYPES_H_
